home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / hobby / ast44src.zip / XCHARTS1.C < prev    next >
C/C++ Source or Header  |  1995-02-11  |  44KB  |  1,199 lines

  1. /*
  2. ** Astrolog (Version 4.40) File: xcharts1.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. #include "astrolog.h"
  38.  
  39.  
  40. #ifdef GRAPH
  41. /*
  42. ******************************************************************************
  43. ** Single Chart Graphics Routines.
  44. ******************************************************************************
  45. */
  46.  
  47. /* Draw a wheel chart, in which the 12 signs and houses are delineated, and  */
  48. /* the planets are inserted in their proper places. This is the default      */
  49. /* graphics chart to generate, as is done when the -v or -w (or no) switches */
  50. /* are included with -X. Draw the aspects in the middle of chart, too.       */
  51.  
  52. void XChartWheel()
  53. {
  54.   real xsign[cSign+1], xhouse[cSign+1], xplanet[objMax], symbol[objMax];
  55.   int cx, cy, i, j;
  56.   real asc, unitx, unity, px, py, temp;
  57.  
  58.   /* Set up variables and temporarily automatically decrease the horizontal */
  59.   /* chart size to leave room for the sidebar if that mode is in effect.    */
  60.  
  61.   if (gs.fText && !us.fVelocity)
  62.     gs.xWin -= xSideT;
  63.   cx = gs.xWin/2 - 1; cy = gs.yWin/2 - 1;
  64.   unitx = (real)cx; unity = (real)cy;
  65.   asc = gs.nLeft ? planet[abs(gs.nLeft)]+90*(gs.nLeft < 0) : house[1];
  66.  
  67.   /* Fill out arrays with the angular degree on the circle of where to    */
  68.   /* place each object, cusp, and sign glyph based on how the chart mode. */
  69.  
  70.   if (gi.nMode == gWheel) {
  71.     for (i = 1; i <= cSign; i++)
  72.       xhouse[i] = PZ(house[i]);
  73.   } else {
  74.     asc -= house[1];
  75.     for (i = 1; i <= cSign; i++)
  76.       xhouse[i] = PZ(ZFromS(i));
  77.   }
  78.   for (i = 1; i <= cSign; i++)
  79.     xsign[i] = PZ(HousePlaceInX(ZFromS(i)));
  80.   for (i = 1; i <= cObj; i++)
  81.     xplanet[i] = PZ(HousePlaceInX(planet[i]));
  82.  
  83.   /* Draw Ascendant/Descendant and Midheaven/Nadir lines across whole chart. */
  84.  
  85.   DrawColor(gi.kiLite);
  86.   DrawDash(cx+POINT1(unitx, 0.99, PX(xhouse[sAri])),
  87.            cy+POINT1(unity, 0.99, PY(xhouse[sAri])),
  88.            cx+POINT1(unitx, 0.99, PX(xhouse[sLib])),
  89.            cy+POINT1(unity, 0.99, PY(xhouse[sLib])), !gs.fColor);
  90.   DrawDash(cx+POINT1(unitx, 0.99, PX(xhouse[sCap])),
  91.            cy+POINT1(unity, 0.99, PY(xhouse[sCap])),
  92.            cx+POINT1(unitx, 0.99, PX(xhouse[sCan])),
  93.            cy+POINT1(unity, 0.99, PY(xhouse[sCan])), !gs.fColor);
  94.  
  95.   /* Draw small five or one degree increments around the zodiac sign ring. */
  96.  
  97.   for (i = 0; i < nDegMax; i ++) {
  98.     temp = PZ(HousePlaceInX((real)i));
  99.     px = PX(temp); py = PY(temp);
  100.     DrawColor(i%5 ? gi.kiGray : gi.kiOn);
  101.     DrawDash(cx+POINT1(unitx, 0.75, px), cy+POINT1(unity, 0.75, py),
  102.       cx+POINT2(unitx, 0.80, px), cy+POINT2(unity, 0.80, py),
  103.       ((!gs.fColor || gs.fPS || gs.fMeta) && i%5)*2);
  104.   }
  105.  
  106.   /* Draw circles for the zodiac sign and house rings. */
  107.  
  108.   DrawColor(gi.kiOn);
  109.   DrawCircle(cx, cy, (int)(unitx*0.95+rRound), (int)(unity*0.95+rRound));
  110.   DrawCircle(cx, cy, (int)(unitx*0.80+rRound), (int)(unity*0.80+rRound));
  111.   DrawCircle(cx, cy, (int)(unitx*0.75+rRound), (int)(unity*0.75+rRound));
  112.   DrawCircle(cx, cy, (int)(unitx*0.65+rRound), (int)(unity*0.65+rRound));
  113.  
  114.   /* Draw the glyphs for the signs and houses themselves. */
  115.  
  116.   for (i = 1; i <= cSign; i++) {
  117.     temp = xsign[i];
  118.     DrawColor(gi.kiOn);
  119.     DrawLine(cx+POINT2(unitx, 0.95, PX(temp)),    /* Draw lines separating */
  120.       cy+POINT2(unity, 0.95, PY(temp)),           /* each sign and house   */
  121.       cx+POINT1(unitx, 0.80, PX(temp)),           /* from each other.      */
  122.       cy+POINT1(unity, 0.80, PY(temp)));
  123.     DrawLine(cx+POINT2(unitx, 0.75, PX(xhouse[i])),
  124.       cy+POINT2(unity, 0.75, PY(xhouse[i])),
  125.       cx+POINT1(unitx, 0.65, PX(xhouse[i])),
  126.       cy+POINT1(unity, 0.65, PY(xhouse[i])));
  127.     if (gs.fColor && i%3 != 1) {                              /* Lines from */
  128.       DrawColor(gi.kiGray);                                   /* each house */
  129.       DrawDash(cx, cy, cx+POINT2(unitx, 0.65, PX(xhouse[i])), /* to center  */
  130.         cy+POINT2(unity, 0.65, PY(xhouse[i])), 1);            /* of wheel.  */
  131.     }
  132.     temp = Midpoint(temp, xsign[Mod12(i+1)]);
  133.     DrawColor(kSignB(i));
  134.     DrawSign(i, cx+POINT1(unitx, 0.875, PX(temp)),
  135.       cy+POINT1(unity, 0.875, PY(temp)));
  136.     temp = Midpoint(xhouse[i], xhouse[Mod12(i+1)]);
  137.     DrawHouse(i, cx+POINT1(unitx, 0.70, PX(temp)),
  138.       cy+POINT1(unity, 0.70, PY(temp)));
  139.   }
  140.   for (i = 1; i <= cObj; i++)    /* Figure out where to put planet glyphs. */
  141.     symbol[i] = xplanet[i];
  142.   FillSymbolRing(symbol);
  143.  
  144.   /* For each planet, draw a small dot indicating where it is, and then */
  145.   /* a line from that point to the planet's glyph.                      */
  146.  
  147.   for (i = cObj; i >= 1; i--) if (FProper(i)) {
  148.     if (gs.fLabel) {
  149.       temp = symbol[i];
  150.       DrawColor(ret[i] < 0.0 ? gi.kiGray : gi.kiOn);
  151.       DrawDash(cx+POINT1(unitx, 0.52, PX(xplanet[i])),
  152.         cy+POINT1(unity, 0.52, PY(xplanet[i])),
  153.         cx+POINT1(unitx, 0.56, PX(temp)),
  154.         cy+POINT1(unity, 0.56, PY(temp)),
  155.         (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  156.       DrawObject(i, cx+POINT1(unitx, 0.60, PX(temp)),
  157.         cy+POINT1(unity, 0.60, PY(temp)));
  158.     } else
  159.       DrawColor(kObjB[i]);
  160.     DrawPoint(cx+POINT1(unitx, 0.50, PX(xplanet[i])),
  161.       cy+POINT1(unity, 0.50, PY(xplanet[i])));
  162.   }
  163.  
  164.   /* Draw lines connecting planets which have aspects between them. */
  165.  
  166.   if (!gs.fAlt) {                /* Don't draw aspects in bonus mode. */
  167.     if (!FCreateGrid(fFalse))
  168.       return;
  169.     for (j = cObj; j >= 2; j--)
  170.       for (i = j-1; i >= 1; i--)
  171.         if (grid->n[i][j] && FProper(i) && FProper(j)) {
  172.           DrawColor(kAspB[grid->n[i][j]]);
  173.           DrawDash(cx+POINT1(unitx, 0.48, PX(xplanet[i])),
  174.             cy+POINT1(unity, 0.48, PY(xplanet[i])),
  175.             cx+POINT1(unitx, 0.48, PX(xplanet[j])),
  176.             cy+POINT1(unity, 0.48, PY(xplanet[j])),
  177.             abs(grid->v[i][j]/60/2));
  178.         }
  179.   }
  180.  
  181.   /* Go draw sidebar with chart information and positions if need be. */
  182.  
  183.   DrawInfo();
  184. }
  185.  
  186.  
  187. /* Draw an astro-graph chart on a map of the world, i.e. the draw the     */
  188. /* Ascendant, Descendant, Midheaven, and Nadir lines corresponding to the */
  189. /* time in the chart. This chart is done when the -L switch is combined   */
  190. /* with the -X switch.                                                    */
  191.  
  192. void XChartAstroGraph()
  193. {
  194.   real planet1[objMax], planet2[objMax],
  195.     end1[cObj*2+1], end2[cObj*2+1],
  196.     symbol1[cObj*2+1], symbol2[cObj*2+1],
  197.     lon = Lon, longm, x, y, z, ad, oa, am, od, dm, lat;
  198.   int unit = gi.nScale, fStroke, lat1 = -60, lat2 = 75, y1, y2, xold1, xold2,
  199.     i, j, k, l;
  200.  
  201.   /* Erase top and bottom parts of map. We don't draw the astro-graph lines */
  202.   /* above certain latitudes, and this gives us room for glyph labels, too. */
  203.  
  204.   y1 = (91-lat1)*gi.nScale;
  205.   y2 = (91-lat2)*gi.nScale;
  206.   DrawColor(gi.kiOff);
  207.   DrawBlock(0, 1, gs.xWin-1, y2-1);
  208.   DrawBlock(0, gs.yWin-2, gs.xWin-1, y1+1);
  209.   DrawColor(gi.kiLite);
  210.   DrawDash(0, gs.yWin/2, gs.xWin-2, gs.yWin/2, 4);    /* Draw equator. */
  211.   DrawColor(gi.kiOn);
  212.   DrawLine(1, y2, gs.xWin-2, y2);
  213.   DrawLine(1, y1, gs.xWin-2, y1);
  214.   for (i = 1; i <= cObj*2; i++)
  215.     end1[i] = end2[i] = -rLarge;
  216.  
  217.   /* Draw small hatches every 5 degrees along edges of world map. */
  218.  
  219.   DrawColor(gi.kiLite);
  220.   for (i = lat1; i <= lat2; i += 5) {
  221.     j = (91-i)*gi.nScale;
  222.     k = (2+(i%10 == 0)+2*(i%30 == 0))*gi.nScaleT;
  223.     DrawLine(1, j, k, j);
  224.     DrawLine(gs.xWin-2, j, gs.xWin-1-k, j);
  225.   }
  226.   for (i = -180; i < 180; i += 5) {
  227.     j = (180-i)*gi.nScale;
  228.     k = (2+(i%10 == 0)+2*(i%30 == 0)+(i%90 == 0))*gi.nScaleT;
  229.     DrawLine(j, y2+1, j, y2+k);
  230.     DrawLine(j, y1-1, j, y1-k);
  231.   }
  232.   if (us.fLatitudeCross) {
  233.     DrawColor(kRainbowB[7]);
  234.     i = (int)((91.0-Lat)*(real)gi.nScale);
  235.     DrawLine(0, i, gs.xWin-1, i);
  236.   }
  237.  
  238. #ifdef MATRIX
  239.   /* Calculate zenith locations of each planet. */
  240.  
  241.   for (i = 1; i <= cObj; i++) if (!ignore[i]) {
  242.     planet1[i] = RFromD(Tropical(planet[i]));
  243.     planet2[i] = RFromD(planetalt[i]);
  244.     EclToEqu(&planet1[i], &planet2[i]);
  245.   }
  246.  
  247.   /* Draw the Midheaven lines and zenith location markings. */
  248.  
  249.   if (lon < 0.0)
  250.     lon += rDegMax;
  251.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  252.     x = RFromD(MC)-planet1[i];
  253.     if (x < 0.0)
  254.       x += 2.0*rPi;
  255.     if (x > rPi)
  256.       x -= 2.0*rPi;
  257.     z = lon+DFromR(x);
  258.     if (z > rDegHalf)
  259.       z -= rDegMax;
  260.     j = (int)(Mod(rDegHalf-z+gs.nRot)*(real)gi.nScale);
  261.     DrawColor(kElemB[eEar]);
  262.     DrawLine(j, y1+unit*4, j, y2-unit*1);
  263.     end2[i*2-1] = (real)j;
  264.     y = DFromR(planet2[i]);
  265.     k = (int)((91.0-y)*(real)gi.nScale);
  266.     if (FBetween((int)y, lat1, lat2)) {
  267.       DrawColor(gi.kiLite);
  268.       DrawBlock(j-1, k-1, j+1, k+1);
  269.       DrawColor(gi.kiOff);
  270.       DrawBlock(j, k, j, k);
  271.     }
  272.  
  273.     /* Draw Nadir lines assuming we aren't in bonus chart mode. */
  274.  
  275.     if (!gs.fAlt) {
  276.       j += 180*gi.nScale;
  277.       if (j > gs.xWin-2)
  278.         j -= (gs.xWin-2);
  279.       end1[i*2-1] = (real)j;
  280.       DrawColor(kElemB[eWat]);
  281.       DrawLine(j, y1+unit*2, j, y2-unit*2);
  282.     }
  283.   }
  284.  
  285.   /* Now, normally, unless we are in bonus chart mode, we will go on to draw */
  286.   /* the Ascendant and Descendant lines here.                                */
  287.  
  288.   longm = RFromD(Mod(MC+lon));
  289.   if (!gs.fAlt) for (i = 1; i <= cObj; i++) if (FProper(i)) {
  290.     xold1 = xold2 = -1000;
  291.  
  292.     /* Hack: Normally we draw the Ascendant and Descendant line segments  */
  293.     /* simultaneously. However, for the PostScript and metafile stroke    */
  294.     /* graphics, this will case the file to get inordinately large due to */
  295.     /* the constant thrashing between the Asc and Desc colors. Hence for  */
  296.     /* these charts only, we'll do two passes for Asc and Desc.           */
  297.     fStroke = gs.fPS || gs.fMeta;
  298.     for (l = 0; l <= fStroke; l++)
  299.  
  300.     for (lat = (real)lat1; lat <= (real)lat2;
  301.       lat += 1.0/(real)(gi.nScale/gi.nScaleT)) {
  302.  
  303.       /* First compute and draw the current segment of Ascendant line. */
  304.  
  305.       j = (int)((91.0-lat)*(real)gi.nScale);
  306.       ad = RTan(planet2[i])*RTan(RFromD(lat));
  307.       if (ad*ad > 1.0)
  308.         ad = rLarge;
  309.       else {
  310.         ad = RAsin(ad);
  311.         oa = planet1[i]-ad;
  312.         if (oa < 0.0)
  313.           oa += 2.0*rPi;
  314.         am = oa-rPiHalf;
  315.         if (am < 0.0)
  316.           am += 2.0*rPi;
  317.         z = longm-am;
  318.         if (z < 0.0)
  319.           z += 2.0*rPi;
  320.         if (z > rPi)
  321.           z -= 2.0*rPi;
  322.         z = DFromR(z);
  323.         k = (int)(Mod(rDegHalf-z+gs.nRot)*(real)gi.nScale);
  324.         if (!fStroke || !l) {
  325.           DrawColor(kElemB[eFir]);
  326.           DrawWrap(xold1, j+gi.nScaleT, k, j, 1, gs.xWin-2);
  327.           if (lat == (real)lat1) {                          /* Line segment */
  328.             DrawLine(k, y1, k, y1+unit*4);                  /* pointing to  */
  329.             end2[i*2] = (real)k;                            /* Ascendant.   */
  330.           }
  331.         } else if (lat == (real)lat1)
  332.           end2[i*2] = (real)k;
  333.         xold1 = k;
  334.       }
  335.  
  336.       /* The curving Ascendant and Descendant lines actually touch each at  */
  337.       /* low latitudes. Sometimes when we start out, a particular planet's  */
  338.       /* lines haven't appeared yet, i.e. we are scanning at a latitude     */
  339.       /* where our planet's lines don't exist. If this is the case, then    */
  340.       /* when they finally do start, draw a thin horizontal line connecting */
  341.       /* the Ascendant and Descendant lines so they don't just start in     */
  342.       /* space. Note that these connected lines aren't labeled with glyphs. */
  343.  
  344.       if (ad == rLarge) {
  345.         if (xold1 >= 0) {
  346.           if (!fStroke || !l) {
  347.             DrawColor(gi.kiGray);
  348.             DrawWrap(xold1, j+1, xold2, j+1, 1, gs.xWin-2);
  349.           }
  350.           lat = rDegQuad;
  351.         }
  352.       } else {
  353.  
  354.       /* Then compute and draw corresponding segment of Descendant line. */
  355.  
  356.         od = planet1[i]+ad;
  357.         dm = od+rPiHalf;
  358.         z = longm-dm;
  359.         if (z < 0.0)
  360.           z += 2.0*rPi;
  361.         if (z > rPi)
  362.           z -= 2.0*rPi;
  363.         z = DFromR(z);
  364.         k = (int)(Mod(rDegHalf-z+gs.nRot)*(real)gi.nScale);
  365.         if (xold2 < 0 && lat > (real)lat1 && (!fStroke || l)) {
  366.           DrawColor(gi.kiGray);
  367.           DrawWrap(xold1, j, k, j, 1, gs.xWin-2);
  368.         }
  369.         if (!fStroke || l) {
  370.           DrawColor(kElemB[eAir]);
  371.           DrawWrap(xold2, j+gi.nScaleT, k, j, 1, gs.xWin-2);
  372.           if (lat == (real)lat1)                            /* Line segment */
  373.             DrawLine(k, y1, k, y1+unit*2);                  /* pointing to  */
  374.         }                                                   /* Descendant.  */
  375.         xold2 = k;
  376.       }
  377.     }
  378. #endif /* MATRIX */
  379.  
  380.     /* Draw segments pointing to top of Ascendant and Descendant lines. */
  381.  
  382.     if (ad != rLarge) {
  383.       DrawColor(kElemB[eFir]);
  384.       DrawLine(xold1, y2, xold1, y2-unit*1);
  385.       DrawColor(kElemB[eAir]);
  386.       DrawLine(k, y2, k, y2-unit*2);
  387.       end1[i*2] = (real)k;
  388.     }
  389.   }
  390.  
  391.   DrawColor(kMainB[8]);
  392.   i = (int)((181.0-Lon)*(real)gi.nScale);
  393.   j = (int)((91.0-Lat)*(real)gi.nScale);
  394.   if (us.fLatitudeCross)
  395.     DrawSpot(i, j);
  396.   else
  397.     DrawPoint(i, j);
  398.  
  399.   /* Determine where to draw the planet glyphs. We have four sets of each    */
  400.   /* planet - each planet's glyph appearing in the chart up to four times -  */
  401.   /* one for each type of line. The Midheaven and Ascendant lines are always */
  402.   /* labeled at the bottom of the chart, while the Nadir and Midheaven lines */
  403.   /* at the top. Therefore we need to place two sets of glyphs, twice.       */
  404.  
  405.   for (i = 1; i <= cObj*2; i++) {
  406.     symbol1[i] = end1[i];
  407.     symbol2[i] = end2[i];
  408.   }
  409.   FillSymbolLine(symbol1);
  410.   FillSymbolLine(symbol2);
  411.  
  412.   /* Now actually draw the planet glyphs. */
  413.  
  414.   for (i = 1; i <= cObj*2; i++) {
  415.     j = (i+1)/2;
  416.     if (FProper(j)) {
  417.       if ((gi.xTurtle = (int)symbol1[i]) > 0 && gs.fLabel) {
  418.         DrawColor(ret[j] < 0.0 ? gi.kiGray : gi.kiOn);
  419.         DrawDash((int)end1[i], y2-unit*2, (int)symbol1[i], y2-unit*4,
  420.           (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  421.         DrawObject(j, gi.xTurtle, y2-unit*10);
  422.       }
  423.       if ((gi.xTurtle = (int)symbol2[i]) > 0) {
  424.         DrawColor(ret[j] < 0.0 ? gi.kiGray : gi.kiOn);
  425.         DrawDash((int)end2[i], y1+unit*4, (int)symbol2[i], y1+unit*8,
  426.           (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  427.         DrawObject(j, gi.xTurtle, y1+unit*14);
  428.         DrawTurtle(szDrawObject[i & 1 ? oMC : oAsc], (int)symbol2[i],
  429.           y1+unit*24-gi.nScaleT);
  430.       }
  431.     }
  432.   }
  433. }
  434.  
  435.  
  436. /* Draw an aspect and midpoint grid in the window, with planets labeled down */
  437. /* the diagonal. This chart is done when the -g switch is combined with the  */
  438. /* -X switch. The chart always has a certain number of cells; hence based    */
  439. /* how the restrictions are set up, there may be blank columns and rows,     */
  440. /* or else only the first number of unrestricted objects will be included.   */
  441.  
  442. void XChartGrid()
  443. {
  444.   char sz[cchSzDef];
  445.   int unit, siz, x, y, i, j, k;
  446.   KI c;
  447.  
  448.   unit = CELLSIZE*gi.nScale; siz = gs.nGridCell*unit;
  449.   if (!FCreateGrid(gs.fAlt))
  450.     return;
  451.  
  452.   /* Loop through each cell in each row and column of grid. */
  453.  
  454.   for (y = 1, j = 0; y <= gs.nGridCell; y++) {
  455.     do {
  456.       j++;
  457.     } while (ignore[j] && j <= cObj);
  458.     DrawColor(gi.kiGray);
  459.     DrawDash(0, y*unit, siz, y*unit, !gs.fColor);
  460.     DrawDash(y*unit, 0, y*unit, siz, !gs.fColor);
  461.     if (j <= cObj) for (x = 1, i = 0; x <= gs.nGridCell; x++) {
  462.       do {
  463.         i++;
  464.       } while (ignore[i] && i <= cObj);
  465.       if (i <= cObj) {
  466.         gi.xTurtle = x*unit-unit/2;
  467.         gi.yTurtle = y*unit-unit/2 -
  468.           (gi.nScale/gi.nScaleT > 2 ? 5*gi.nScaleT : 0);
  469.         k = grid->n[i][j];
  470.  
  471.         /* If this is an aspect cell, draw glyph of aspect in effect. */
  472.  
  473.         if (gs.fAlt ? x > y : x < y) {
  474.           if (k) {
  475.             DrawColor(c = kAspB[k]);
  476.             DrawAspect(k, gi.xTurtle, gi.yTurtle);
  477.           }
  478.  
  479.         /* If this is a midpoint cell, draw glyph of sign of midpoint. */
  480.  
  481.         } else if (gs.fAlt ? x < y : x > y) {
  482.           DrawColor(c = kSignB(grid->n[i][j]));
  483.           DrawSign(grid->n[i][j], gi.xTurtle, gi.yTurtle);
  484.  
  485.         /* For cells on main diagonal, draw glyph of planet. */
  486.  
  487.         } else {
  488.           DrawColor(gi.kiLite);
  489.           DrawEdge((y-1)*unit, (y-1)*unit, y*unit, y*unit);
  490.           DrawObject(i, gi.xTurtle, gi.yTurtle);
  491.         }
  492.  
  493.         /* When the scale size is 300+, we can print text in each cell: */
  494.  
  495.         if (gi.nScale/gi.nScaleT > 2 && gs.fLabel) {
  496.           k = abs(grid->v[i][j]);
  497.  
  498.           /* For the aspect portion, print the orb in degrees and minutes. */
  499.  
  500.           if (gs.fAlt ? x > y : x < y) {
  501.             if (grid->n[i][j])
  502.               sprintf(sz, "%c%d %02d'", k != grid->v[i][j] ? (us.fAppSep ?
  503.                 'a' : '-') : (us.fAppSep ? 's' : '+'), k/60, k%60);
  504.             else
  505.               sprintf(sz, "");
  506.  
  507.           /* For the midpoint portion, print the degrees and minutes. */
  508.  
  509.           } else if (gs.fAlt ? x < y : x > y)
  510.             sprintf(sz, "%2d %02d'", k/60, k%60);
  511.  
  512.           /* For the main diagonal, print degree and sign of each planet. */
  513.  
  514.           else {
  515.             c = kSignB(grid->n[i][j]);
  516.             sprintf(sz, "%c%c%c %02d", chSig3(grid->n[i][j]), k);
  517.           }
  518.           DrawColor(c);
  519.           DrawSz(sz, x*unit-unit/2, y*unit-3*gi.nScaleT, dtBottom);
  520.         }
  521.       }
  522.     }
  523.   }
  524. }
  525.  
  526.  
  527. /* Draw the local horizon, and draw in the planets where they are at the */
  528. /* time in question, as done when the -Z is combined with the -X switch. */
  529.  
  530. void XChartHorizon()
  531. {
  532.   real lat, lonz[objMax], latz[objMax], azi[objMax], alt[objMax];
  533.   int x[objMax], y[objMax], m[objMax], n[objMax],
  534.     cx, cy, unit, x1, y1, x2, y2, xs, ys, i, j, k, l;
  535.   char sz[2];
  536.  
  537.   unit = Max(12, 6*gi.nScale);
  538.   x1 = unit; y1 = unit; x2 = gs.xWin-1-unit; y2 = gs.yWin-1-unit;
  539.   unit = 12*gi.nScale;
  540.   xs = x2-x1; ys = y2-y1; cx = (x1+x2)/2; cy = (y1+y2)/2;
  541.  
  542.   /* Make a slightly smaller rectangle within the window to draw the planets */
  543.   /* in. Make segments on all four edges marking 5 degree increments.        */
  544.  
  545.   DrawColor(gi.kiLite);
  546.   for (i = 5; i < 180; i += 5) {
  547.     j = y1+(int)((real)i*(real)ys/rDegHalf);
  548.     k = (2+(i%10 == 0)+2*(i%30 == 0))*gi.nScaleT;
  549.     DrawLine(x1+1, j, x1+1+k, j);
  550.     DrawLine(x2-1, j, x2-1-k, j);
  551.   }
  552.   sz[1] = chNull;
  553.   for (i = 5; i < nDegMax; i += 5) {
  554.     j = x1+(int)((real)i*(real)xs/rDegMax);
  555.     k = (2+(i%10 == 0)+2*(i%30 == 0))*gi.nScaleT;
  556.     DrawLine(j, y1+1, j, y1+1+k);
  557.     DrawLine(j, y2-1, j, y2-1-k);
  558.     if (i % 90 == 0) {
  559.       *sz = *szDir[i/90 & 3];
  560.       DrawSz(sz, j, y1-2*gi.nScaleT, dtBottom);
  561.     }
  562.   }
  563.  
  564.   /* Draw vertical lines dividing our rectangle into four areas. In our     */
  565.   /* local space chart, the middle line represents due south, the left line */
  566.   /* due east, the right line due west, and the edges due north. A fourth   */
  567.   /* horizontal line divides that which is above and below the horizon.     */
  568.  
  569.   DrawColor(gi.kiGray);
  570.   DrawDash(cx, y1, cx, y2, 1);
  571.   DrawDash((cx+x1)/2, y1, (cx+x1)/2, y2, 1);
  572.   DrawDash((cx+x2)/2, y1, (cx+x2)/2, y2, 1);
  573.   DrawColor(gi.kiOn);
  574.   DrawEdge(x1, y1, x2, y2);
  575.   DrawDash(x1, cy, x2, cy, 1);
  576.  
  577.   /* Calculate the local horizon coordinates of each planet. First convert */
  578.   /* zodiac position and declination to zenith longitude and latitude.     */
  579.  
  580.   lat = RFromD(Lat);
  581.   for (i = 1; i <= cObj; i++) if (!ignore[i] || i == oMC) {
  582.     lonz[i] = RFromD(Tropical(planet[i])); latz[i] = RFromD(planetalt[i]);
  583.     EclToEqu(&lonz[i], &latz[i]);
  584.   }
  585.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  586.     lonz[i] = RFromD(Mod(DFromR(lonz[oMC]-lonz[i]+rPiHalf)));
  587.     EquToLocal(&lonz[i], &latz[i], rPiHalf-lat);
  588.     azi[i] = rDegMax-DFromR(lonz[i]); alt[i] = DFromR(latz[i]);
  589.     x[i] = x1+(int)((real)xs*(Mod(rDegQuad-azi[i]))/rDegMax+rRound);
  590.     y[i] = y1+(int)((real)ys*(rDegQuad-alt[i])/rDegHalf+rRound);
  591.     m[i] = x[i]; n[i] = y[i]+unit/2;
  592.   }
  593.  
  594.   /* As in the DrawGlobe() routine, we now determine where to draw the   */
  595.   /* glyphs in relation to the actual points, so that the glyphs aren't  */
  596.   /* drawn on top of each other if possible. Again, we assume that we'll */
  597.   /* put the glyph right under the point, unless there would be some     */
  598.   /* overlap and the above position is better off.                       */
  599.  
  600.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  601.     k = l = gs.xWin+gs.yWin;
  602.     for (j = 1; j < i; j++) if (FProper(j)) {
  603.       k = Min(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  604.       l = Min(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  605.     }
  606.     if (k < unit || l < unit)
  607.       if (k < l)
  608.         n[i] -= unit;
  609.   }
  610.   for (i = cObj; i >= 1; i--) if (FProper(i))    /* Draw planet's glyph. */
  611.     DrawObject(i, m[i], n[i]);
  612.   for (i = cObj; i >= 1; i--) if (FProper(i)) {
  613.     DrawColor(kObjB[i]);
  614.     if (!gs.fAlt || i > oNorm)
  615.       DrawPoint(x[i], y[i]);      /* Draw small or large dot */
  616.     else                          /* near glyph indicating   */
  617.       DrawSpot(x[i], y[i]);       /* exact local location.   */
  618.   }
  619. }
  620.  
  621.  
  622. /* Draw the local horizon, and draw in the planets where they are at the  */
  623. /* time in question. This chart is done when the -Z0 is combined with the */
  624. /* -X switch. This is an identical function to XChartHorizon(); however,  */
  625. /* that routine's chart is entered on the horizon and meridian. Here we   */
  626. /* center the chart around the center of the sky straight up from the     */
  627. /* local horizon, with the horizon itself being an encompassing circle.   */
  628.  
  629. void XChartHorizonSky()
  630. {
  631.   real lat, rx, ry, s, sqr2,
  632.     lonz[objMax], latz[objMax], azi[objMax], alt[objMax];
  633.   int x[objMax], y[objMax], m[objMax], n[objMax],
  634.     cx, cy, unit, x1, y1, x2, y2, xs, ys, i, j, k, l;
  635.  
  636.   unit = Max(12, 6*gi.nScale);
  637.   x1 = unit; y1 = unit; x2 = gs.xWin-1-unit; y2 = gs.yWin-1-unit;
  638.   unit = 12*gi.nScale;
  639.   xs = x2-x1; ys = y2-y1; cx = (x1+x2)/2; cy = (y1+y2)/2;
  640.  
  641.   /* Draw a circle in window to indicate horizon line, lines dividing   */
  642.   /* the window into quadrants to indicate n/s and w/e meridians, and   */
  643.   /* segments on these lines and the edges marking 5 degree increments. */
  644.  
  645.   sqr2 = RSqr(2.0);
  646.   DrawColor(gi.kiGray);
  647.   DrawDash(cx, y1, cx, y2, 1);
  648.   DrawDash(x1, cy, x2, cy, 1);
  649.   DrawColor(gi.kiLite);
  650.   for (i = -125; i <= 125; i += 5) {
  651.     k = (2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0))*gi.nScaleT;
  652.     s = 1.0/(rDegQuad*sqr2);
  653.     j = cy+(int)(s*ys/2*i);
  654.     DrawLine(cx-k, j, cx+k, j);
  655.     j = cx+(int)(s*xs/2*i);
  656.     DrawLine(j, cy-k, j, cy+k);
  657.   }
  658.   for (i = 5; i < 55; i += 5) {
  659.     k = (2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0))*gi.nScaleT;
  660.     s = 1.0/(rDegHalf-rDegQuad*sqr2);
  661.     j = (int)(s*ys/2*i);
  662.     DrawLine(x1, y1+j, x1+k, y1+j);
  663.     DrawLine(x1, y2-j, x1+k, y2-j);
  664.     DrawLine(x2, y1+j, x2-k, y1+j);
  665.     DrawLine(x2, y2-j, x2-k, y2-j);
  666.     j = (int)(s*xs/2*i);
  667.     DrawLine(x1+j, y1, x1+j, y1+k);
  668.     DrawLine(x2-j, y1, x2-j, y1+k);
  669.     DrawLine(x1+j, y2, x1+j, y2-k);
  670.     DrawLine(x2-j, y2, x2-j, y2-k);
  671.   }
  672.   DrawSz("N", cx, y1-2*gi.nScaleT, dtBottom);
  673.   DrawSz("E", x1/2, cy+2*gi.nScaleT, dtCent);
  674.   DrawSz("W", (gs.xWin+x2)/2, cy+2*gi.nScaleT, dtCent);
  675.   if (!gs.fText)
  676.     DrawSz("S", cx, gs.yWin-3*gi.nScaleT, dtBottom);
  677.   rx = xs/2/sqr2; ry = ys/2/sqr2;
  678.   DrawColor(gi.kiOn);
  679.   DrawEdge(x1, y1, x2, y2);
  680.   DrawCircle(cx, cy, (int)rx, (int)ry);
  681.   for (i = 0; i < nDegMax; i += 5) {
  682.     k = (2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0))*gi.nScaleT;
  683.     DrawLine(cx+(int)((rx-k)*RCosD((real)i)), cy+(int)((ry-k)*RSinD((real)i)),
  684.       cx+(int)((rx+k)*RCosD((real)i)), cy+(int)((ry+k)*RSinD((real)i)));
  685.   }
  686.  
  687.   /* Calculate the local horizon coordinates of each planet. First convert */
  688.   /* zodiac position and declination to zenith longitude and latitude.     */
  689.  
  690.   lat = RFromD(Lat);
  691.   for (i = 1; i <= cObj; i++) if (!ignore[i] || i == oMC) {
  692.     lonz[i] = RFromD(Tropical(planet[i])); latz[i] = RFromD(planetalt[i]);
  693.     EclToEqu(&lonz[i], &latz[i]);
  694.   }
  695.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  696.     lonz[i] = RFromD(Mod(DFromR(lonz[oMC]-lonz[i]+rPiHalf)));
  697.     EquToLocal(&lonz[i], &latz[i], rPiHalf-lat);
  698.     azi[i] = rDegMax-DFromR(lonz[i]); alt[i] = rDegQuad-DFromR(latz[i]);
  699.     s = alt[i]/rDegQuad;
  700.     x[i] = cx+(int)(rx*s*RCosD(rDegHalf+azi[i])+rRound);
  701.     y[i] = cy+(int)(ry*s*RSinD(rDegHalf+azi[i])+rRound);
  702.     if (!FOnWin(x[i], y[i]))
  703.       x[i] = -1000;
  704.     m[i] = x[i]; n[i] = y[i]+unit/2;
  705.   }
  706.  
  707.   /* As in the DrawGlobe() routine, we now determine where to draw the   */
  708.   /* glyphs in relation to the actual points, so that the glyphs aren't  */
  709.   /* drawn on top of each other if possible. Again, we assume that we'll */
  710.   /* put the glyph right under the point, unless there would be some     */
  711.   /* overlap and the above position is better off.                       */
  712.  
  713.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  714.     k = l = gs.xWin+gs.yWin;
  715.     for (j = 1; j < i; j++) if (FProper(j)) {
  716.       k = Min(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  717.       l = Min(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  718.     }
  719.     if (k < unit || l < unit)
  720.       if (k < l)
  721.         n[i] -= unit;
  722.   }
  723.   for (i = cObj; i >= 1; i--) if (m[i] >= x1 && FProper(i))  /* Draw glyph. */
  724.     DrawObject(i, m[i], n[i]);
  725.   for (i = cObj; i >= 1; i--) if (x[i] >= y1 && FProper(i)) {
  726.     DrawColor(kObjB[i]);
  727.     if (!gs.fAlt || i > oNorm)
  728.       DrawPoint(x[i], y[i]);      /* Draw small or large dot */
  729.     else                          /* near glyph indicating   */
  730.       DrawSpot(x[i], y[i]);       /* exact local location.   */
  731.   }
  732. }
  733.  
  734.  
  735. /* Draw a chart depicting an aerial view of the solar system in space, with */
  736. /* all the planets drawn around the Sun, and the specified central planet   */
  737. /* in the middle, as done when the -S is combined with the -X switch.       */
  738.  
  739. void XChartOrbit()
  740. {
  741.   int x[objMax], y[objMax], m[objMax], n[objMax],
  742.     cx = gs.xWin / 2, cy = gs.yWin / 2, unit, x1, y1, x2, y2, i, j, k, l;
  743.   real sx, sy, sz = 30.0, xp, yp, a;
  744.  
  745.   unit = Max(gs.fText*12, 6*gi.nScale);
  746.   x1 = unit; y1 = unit; x2 = gs.xWin-1-unit; y2 = gs.yWin-1-unit;
  747.   unit = 12*gi.nScale;
  748.  
  749.   /* Determine the scale of the chart. For a scale size of 400+, make the */
  750.   /* graphic 1 AU in radius (just out to Earth's orbit). For 300, make    */
  751.   /* the chart 6 AU in radius (enough for inner planets out to asteroid   */
  752.   /* belt). For a scale of 200, make window 30 AU in radius (enough for   */
  753.   /* planets out to Neptune). For scale of 100, make it 90 AU in radius   */
  754.   /* (enough for all planets including the orbits of the uranians.)       */
  755.  
  756.   if (gi.nScale/gi.nScaleT < 2)
  757.     sz = 90.0;
  758.   else if (gi.nScale/gi.nScaleT == 3)
  759.     sz = 6.0;
  760.   else if (gi.nScale/gi.nScaleT > 3)
  761.     sz = 1.0;
  762.   sx = (real)(cx-x1)/sz; sy = (real)(cy-y1)/sz;
  763.   for (i = 0; i <= oNorm; i++) if (FProper(i)) {
  764.  
  765.     /* Determine what glyph corresponds to our current planet. Normally the */
  766.     /* array indices are the same, however we have to do some swapping for  */
  767.     /* non-geocentric based charts where a planet gets replaced with Earth. */
  768.  
  769.     if (us.objCenter == 0)
  770.       j = i < oMoo ? 1-i : i;
  771.     else if (us.objCenter == 1)
  772.       j = i;
  773.     else
  774.       j = i == 0 ? us.objCenter : (i == us.objCenter ? 0 : i);
  775.     xp = spacex[j]; yp = spacey[j];
  776.     x[i] = cx-(int)(xp*sx); y[i] = cy+(int)(yp*sy);
  777.     m[i] = x[i]; n[i] = y[i]+unit/2;
  778.   }
  779.  
  780.   /* As in the DrawGlobe() routine, we now determine where to draw the   */
  781.   /* glyphs in relation to the actual points, so that the glyphs aren't  */
  782.   /* drawn on top of each other if possible. Again, we assume that we'll */
  783.   /* put the glyph right under the point, unless there would be some     */
  784.   /* overlap and the above position is better off.                       */
  785.  
  786.   for (i = 0; i <= oNorm; i++) if (FProper(i)) {
  787.     k = l = gs.xWin+gs.yWin;
  788.     for (j = 0; j < i; j++) if (FProper(j)) {
  789.       k = Min(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  790.       l = Min(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  791.     }
  792.     if (k < unit || l < unit)
  793.       if (k < l)
  794.         n[i] -= unit;
  795.   }
  796.  
  797.   /* Draw the 12 sign boundaries from the center body to edges of screen. */
  798.  
  799.   a = Mod(DFromR(Angle(spacex[oJup], spacey[oJup]))-planet[oJup]);
  800.   DrawColor(gi.kiGray);
  801.   for (i = 0; i < cSign; i++) {
  802.     k = cx+2*(int)((real)cx*RCosD((real)i*30.0+a));
  803.     l = cy+2*(int)((real)cy*RSinD((real)i*30.0+a));
  804.     DrawClip(cx, cy, k, l, x1, y1, x2, y2, 1);
  805.   }
  806.   DrawColor(gi.kiLite);
  807.   DrawEdge(x1, y1, x2, y2);
  808.   for (i = oNorm; i >= 0; i--)
  809.     if (FProper(i) && FInRect(m[i], n[i], x1, y1, x2, y2))
  810.       DrawObject(i, m[i], n[i]);
  811.   for (i = oNorm; i >= 0; i--)
  812.     if (FProper(i) && FInRect(x[i], y[i], x1, y1, x2, y2)) {
  813.       DrawColor(kObjB[i]);
  814.       if (!gs.fAlt || i > oNorm)
  815.         DrawPoint(x[i], y[i]);      /* Draw small or large dot */
  816.       else                          /* near glyph indicating   */
  817.         DrawSpot(x[i], y[i]);       /* exact orbital location. */
  818.     }
  819. }
  820.  
  821.  
  822. /* Draw an arrow from one point to another, a line with an arrowhead at the */
  823. /* ending point. The size of the arrowhead is based on current scale size,  */
  824. /* and the line segment is actually shorter and doesn't touch either        */
  825. /* endpoint by the same amount. This is used by XChartDispositor() below.   */
  826.  
  827. void DrawArrow(x1, y1, x2, y2)
  828. int x1, y1, x2, y2;
  829. {
  830.   real r, s, a;
  831.  
  832.   r = DFromR(Angle((real)(x2-x1), (real)(y2-y1)));
  833.   s = (real)(gi.nScale*gi.nScaleT*8);
  834.   x1 += (int)(s*RCosD(r)); y1 += (int)(s*RSinD(r));    /* Shrink line by    */
  835.   x2 -= (int)(s*RCosD(r)); y2 -= (int)(s*RSinD(r));    /* the scale amount. */
  836.   s = (real)(gi.nScale*gi.nScaleT)*4.5;
  837.   DrawLine(x1, y1, x2, y2);                            /* Main segment. */
  838.   for (a = -1.0; a <= 1.0; a += 2.0)
  839.     DrawLine(x2, y2, x2 + (int)(s*RCosD(r + a*135.0)), /* The two arrow     */
  840.       y2 + (int)(s*RSinD(r + a*135.0)));               /* head line pieces. */
  841. }
  842.  
  843.  
  844. /* Draw dispositor graphs for the 10 main planets, as done when the -j is   */
  845. /* combined with the -X switch. Four graphs are drawn, one in each screen   */
  846. /* quadrant. A dispositor graph may be based on the sign or house position, */
  847. /* and the planets may be arranged in a hierarchy or a wheel format.        */
  848.  
  849. void XChartDispositor()
  850. {
  851.   int oDis[oMain+1], dLev[oMain+1], cLev[oMain+1], xo[oMain+1], yo[oMain+1];
  852.   real xCirc[oMain+1], yCirc[oMain+1];
  853.   char sz[cchSzDef];
  854.   int xLev, yLev, xSub, ySub, cx0, cy0, cx, cy, i, j, k;
  855.  
  856.   /* Set up screen positions of the 10 planets for the wheel graphs. */
  857.  
  858.   cx0 = gs.xWin / 2; cy0 = gs.yWin / 2;
  859.   for (i = 1; i <= oMain; i++) {
  860.     if ((j = (180-(i-1)*360/oMain)) < 0)
  861.       j += nDegMax;
  862.     xCirc[i] = (real)cx0*0.4*RCosD((real)j);
  863.     yCirc[i] = (real)cy0*0.4*RSinD((real)j);
  864.   }
  865.  
  866.   /* Loop over the two basic dispositor types: sign based and house based. */
  867.  
  868.   for (xSub = 0; xSub <= 1; xSub++) {
  869.     cx = xSub * cx0 + cx0 / 2;
  870.  
  871.     /* For each planet, get its dispositor planet for current graph type. */
  872.  
  873.     for (i = 1; i <= oMain; i++) {
  874.       oDis[i] = rules[xSub ? inhouse[i] : SFromZ(planet[i])];
  875.       dLev[i] = 1;
  876.     }
  877.  
  878.     /* Determine the final dispositors (including mutual reception loops). */
  879.  
  880.     do {
  881.       j = fFalse;
  882.       for (i = 1; i <= oMain; i++)
  883.         cLev[i] = fFalse;
  884.       for (i = 1; i <= oMain; i++)
  885.         if (dLev[i]) 
  886.           cLev[oDis[i]] = fTrue;
  887.       for (i = 1; i <= oMain; i++)    /* A planet isn't a final dispositor */
  888.         if (dLev[i] && !cLev[i]) {    /* if nobody is pointing to it.      */
  889.           dLev[i] = 0;
  890.           j = fTrue;
  891.         }
  892.     } while (j);
  893.  
  894.     /* Determine the level of each planet, i.e. how many times you have to */
  895.     /* jump to your dispositor before reaching a final, with finals == 1.  */
  896.  
  897.     do {
  898.       j = fFalse;
  899.       for (i = 1; i <= oMain; i++)
  900.         if (!dLev[i]) {
  901.           if (!dLev[oDis[i]])
  902.             j = fTrue;
  903.           else                              /* If my dispositor already has */
  904.             dLev[i] = dLev[oDis[i]] + 1;    /* a level, mine is one more.   */
  905.         }
  906.     } while (j);
  907.  
  908.     /* Count the number of planets at each dispositor level. */
  909.  
  910.     for (i = 1; i <= oMain; i++)
  911.       cLev[i] = 0;
  912.     for (i = 1; i <= oMain; i++)
  913.       cLev[dLev[i]]++;
  914.  
  915.     /* Count the number of levels total, and max planets on any one level. */
  916.  
  917.     xLev = yLev = 0;
  918.     for (i = 1; i <= oMain; i++)
  919.       if (cLev[i]) {
  920.         yLev = i;
  921.         if (cLev[i] > xLev)
  922.           xLev = cLev[i];
  923.       }
  924.  
  925.     /* Loop over our two dispositor display formats: hierarchy and wheel. */
  926.  
  927.     for (ySub = 0; ySub <= 1; ySub++) {
  928.       cy = ySub * cy0 + cy0 / 2;
  929.       sprintf(sz, "%s dispositor %s.", xSub ? "House" : "Sign",
  930.         ySub ? "wheel" : "hierarchy");
  931.       DrawColor(gi.kiLite);
  932.       DrawSz(sz, cx, ySub * cy0 + 3*gi.nScaleT, dtTop);
  933.  
  934.       if (ySub) {
  935.  
  936.         /* Draw a graph in wheel format. */
  937.  
  938.         for (i = 1; i <= oMain; i++) {
  939.           DrawObject(i, cx + (int)xCirc[i], cy + (int)yCirc[i]);
  940.           j = oDis[i];
  941.           if (j != i) {
  942.             if (dLev[i] < 2)
  943.               DrawColor(gi.kiOn);
  944.             else
  945.               DrawColor(kObjB[i]);
  946.             DrawArrow(cx + (int)xCirc[i], cy + (int)yCirc[i],
  947.               cx + (int)xCirc[j], cy + (int)yCirc[j]);
  948.           }
  949.           if (!gs.fAlt && (j == i || dLev[i] < 2)) {
  950.             DrawColor(j == i ? gi.kiOn : gi.kiGray);
  951.             DrawCircle(cx + (int)xCirc[i], cy + (int)yCirc[i],
  952.               7*gi.nScale*gi.nScaleT, 7*gi.nScale*gi.nScaleT);
  953.           }
  954.         }
  955.       } else {
  956.  
  957.         /* For level hierarchies, first figure out the screen coordinates    */
  958.         /* for each planet, based on its level, total levels, and max width. */
  959.  
  960.         for (i = 1; i <= oMain; i++) {
  961.           yo[i] = cy0*(dLev[i]*2-1)/(yLev*2);
  962.           k = 0;
  963.           for (j = 1; j < i; j++)
  964.             if (dLev[i] == dLev[j])
  965.               k = j;
  966.           if (k)
  967.             xo[i] = xo[k] + cx0/xLev;    /* One right of last one on level. */
  968.           else
  969.             xo[i] = cx - ((cx0/xLev)*(cLev[dLev[i]]-1)/2);
  970.         }
  971.  
  972.         /* Draw graph in level hierarchy format. */
  973.  
  974.         for (i = 1; i <= oMain; i++) {
  975.           DrawObject(i, xo[i], yo[i]);  
  976.           j = oDis[i];
  977.           if (j != i) {
  978.             if (dLev[i] < 2) {
  979.               if (abs(xo[i] - xo[j]) < cx0/xLev*3/2) {
  980.                 DrawColor(gi.kiOn);
  981.                 DrawArrow(xo[i], yo[i], xo[j], yo[j]);
  982.               }
  983.               DrawColor(gi.kiGray);
  984.             } else {
  985.               DrawColor(kObjB[i]);
  986.               DrawArrow(xo[i], yo[i], xo[j], yo[j]);
  987.             }
  988.           } else
  989.             DrawColor(gi.kiOn);
  990.           if (!gs.fAlt && dLev[i] < 2)
  991.             DrawCircle(xo[i], yo[i],
  992.               7*gi.nScale*gi.nScaleT, 7*gi.nScale*gi.nScaleT);
  993.         }
  994.       }
  995.     }
  996.   }
  997.  
  998.   /* Draw boundary lines between the four separate dispositor graphs. */
  999.  
  1000.   if (gs.fBorder) {
  1001.     DrawColor(gi.kiLite);
  1002.     DrawBlock(cx0, 0, cx0, gs.yWin);
  1003.     DrawBlock(0, cy0, gs.xWin, cy0);
  1004.   }
  1005. }
  1006.  
  1007.  
  1008. /* Draw a graphical calendar on the screen for the chart month, with     */
  1009. /* numbers in boxes, as done when the -K is combined with the -X switch. */
  1010.  
  1011. void XChartCalendar()
  1012. {
  1013.   char sz[cchSzDef];
  1014.   int day, cday, dayHi, cweek, xunit, yunit, x1, y1, x, y, s;
  1015.  
  1016.   day = DayOfWeek(Mon, 1, Yea);    /* Day of week of 1st of month.     */
  1017.   cday = DaysInMonth(Mon, Yea);    /* Count of days in the month.      */
  1018.   dayHi = DayInMonth(Mon, Yea);    /* Number of last day in the month. */
  1019.   cweek = us.fCalendarYear ? 6 : (day + cday + 6) / 7;   /* Week rows. */
  1020.   xunit = gs.xWin/8;               /* Hor. pixel size of each day box. */
  1021.   yunit = gs.yWin/(cweek+2);       /* Ver. pixel size of each day box. */
  1022.   x1 = (gs.xWin - xunit*7) / 2;    /* Blank space to left of calendar. */
  1023.   y1 = yunit*3/2;                  /* Blank space to top of calendar.  */
  1024.  
  1025.   /* Print the month and year in big letters at top of chart. */
  1026.  
  1027.   DrawColor(gi.kiOn);
  1028.   sprintf(sz, "%s, %d", szMonth[Mon], Yea);
  1029.   s = gi.nScaleT;
  1030.   gi.nScaleT = Min((yunit*3/2-yFontT*gi.nScale) / yFont,
  1031.     gs.xWin/CchSz(sz) / xFont);
  1032.   gi.nScaleT = Max(gi.nScaleT-1, 1);
  1033.   DrawSz(sz, gs.xWin/2, (yunit*3/2-yFont*gi.nScale)/2, dtCent);
  1034.  
  1035.   /* Draw the grid of boxes for the days. */
  1036.  
  1037.   gi.nScaleT = gi.nScale;
  1038.   for (x = 0; x <= 7; x++) {
  1039.  
  1040.     /* Print days of week at top of each column (abbreviated if need be). */
  1041.  
  1042.     if (xunit / xFontT < 9)
  1043.       sprintf(sz, "%c%c%c", chDay3(x));
  1044.     else
  1045.       sprintf(sz, "%s", szDay[x]);
  1046.     if (x < 7) {
  1047.       DrawColor(kRainbowB[3]);
  1048.       DrawSz(sz, x1 + x*xunit + xunit/2, y1 - s*3, dtBottom);
  1049.       DrawColor(kRainbowB[5]);
  1050.     }
  1051.     DrawLine(x1 + x*xunit, y1, x1 + x*xunit, y1 + cweek*yunit);
  1052.   }
  1053.   for (y = 0; y <= cweek; y++)
  1054.     DrawLine(x1, y1 + y*yunit, x1 + 7*xunit, y1 + y*yunit);
  1055.  
  1056.   /* Actually draw the day numbers in their appropriate boxes. */
  1057.  
  1058.   x = day; y = 0;
  1059.   for (day = 1; day <= dayHi; day = AddDay(Mon, day, Yea, 1)) {
  1060.     sprintf(sz, gs.fText ? "%2d" : "%d", day);
  1061.     DrawColor(day == Day && gs.fLabel ? kRainbowB[4] :
  1062.       (x <= 0 || x >= 6 ? kRainbowB[1] : gi.kiLite));
  1063.     if (!gs.fAlt)
  1064.       DrawSz(sz, x1 + x*xunit + s*2, y1 + y*yunit + s*4, dtLeft | dtTop);
  1065.     else
  1066.       DrawSz(sz, x1 + x*xunit + xunit/2,
  1067.         y1 + y*yunit + yunit/2 + gi.nScale, dtCent);
  1068.     if (++x >= 7) {
  1069.       x = 0;
  1070.       y++;
  1071.     }
  1072.   }
  1073.   gi.nScaleT = s;
  1074. }
  1075.  
  1076.  
  1077. /* Draw a chart showing a graphical ephemeris for the given month (or year */
  1078. /* if -Ey in effect), with the date on the vertical access and the zodiac  */
  1079. /* on the horizontal, as done when the -E is combined with the -X switch.  */
  1080.  
  1081. void XChartEphemeris()
  1082. {
  1083.   real symbol[cObj*2+1], objSav[objMax];
  1084.   char sz[4];
  1085.   int yea, unit = 6*gi.nScale, daytot, d = 1, day, mon, monsiz,
  1086.     x1, y1, x2, y2, xs, ys, m, n, u, v, i, j;
  1087.  
  1088.   yea = us.nEphemYears;    /* Is this -Ey -X or just -E -X? */
  1089.   if (yea) {
  1090.     daytot = DayInYearHi(Yea);
  1091.     day = 1; mon = 1; monsiz = 31;
  1092.   } else
  1093.     daytot = DayInMonth(Mon, Yea);
  1094.   x1 = yea ? 30 : 24; y1 = unit*2; x2 = gs.xWin - x1; y2 = gs.yWin - y1;
  1095.   xs = x2 - x1; ys = y2 - y1;
  1096.  
  1097.   /* Display glyphs of the zodiac along the bottom axis. */
  1098.  
  1099.   for (i = 1; i <= cSign+1; i++) {
  1100.     m = x1 + xs * (i-1) / 12;
  1101.     j = i > cSign ? 1 : i;
  1102.     DrawColor(kSignB(j));
  1103.     DrawSign(j, m, y2 + unit);
  1104.     DrawColor(gi.kiGray);
  1105.     DrawDash(m, y1, m, y2, 2);
  1106.   }
  1107.  
  1108.   /* Loop and display planet movements for one day segment. */
  1109.  
  1110.   while (d <= daytot + 1) {
  1111.     n = v;
  1112.     v = y1 + NMultDiv(ys, d-1, daytot);
  1113.     if (!yea || day == 1) {
  1114.       DrawColor(gi.kiGray);
  1115.       DrawDash(x1, v, x2, v, 1);    /* Marker line for day or month. */
  1116.     }
  1117.     if (d > 1)
  1118.       for (i = 1; i <= cObj; i++)
  1119.         objSav[i] = planet[i];
  1120.     if (yea) {
  1121.       MM = mon; DD = day;
  1122.     } else {
  1123.       MM = Mon; DD = d;
  1124.     }
  1125.     YY = Yea; TT = 0.0; SS = us.dstDef; ZZ = us.zonDef;
  1126.     OO = us.lonDef; AA = us.latDef;
  1127.     CastChart(fTrue);
  1128.  
  1129.     /* Draw planet glyphs along top of chart. */
  1130.  
  1131.     if (d < 2) {
  1132.       for (i = 1; i <= cObj; i++) {
  1133.         symbol[i*2-1] = -rLarge;
  1134.         if (!FProper(i) || (i == oMoo && gs.fAlt))
  1135.           symbol[i*2] = -rLarge;
  1136.         else
  1137.           symbol[i*2] = planet[i];
  1138.       }
  1139.       FillSymbolLine(symbol);
  1140.       for (i = cObj; i >= 1; i--)
  1141.         if (symbol[i*2] >= 0.0)
  1142.           DrawObject(i, x1 + (int)((real)xs * symbol[i*2] / rDegMax), unit);
  1143.  
  1144.     /* Draw a line segment for each object during this time section. */
  1145.  
  1146.     } else
  1147.       for (i = cObj; i >= 1; i--) {
  1148.         if (!FProper(i) || (i == oMoo && gs.fAlt))
  1149.           continue;
  1150.         m = x1 + (int)((real)xs * objSav[i] / rDegMax);
  1151.         u = x1 + (int)((real)xs * planet[i] / rDegMax);
  1152.         DrawColor(kObjB[i]);
  1153.         DrawWrap(m, n, u, v, x1, x2);
  1154.       }
  1155.  
  1156.     /* Label months or days in the month along the left and right edges. */
  1157.  
  1158.     if (d <= daytot && (!yea || day == 1)) {
  1159.       if (yea) {
  1160.         sprintf(sz, "%c%c%c", chMon3(mon));
  1161.         i = (mon == Mon);
  1162.       } else {
  1163.         sprintf(sz, "%2d", d);
  1164.         i = (d == Day);
  1165.       }
  1166.       DrawColor(i ? gi.kiOn : gi.kiLite);
  1167.       DrawSz(sz,     xFont   *gi.nScaleT, v + (yFont-2)*gi.nScaleT,
  1168.         dtLeft | dtBottom);
  1169.       DrawSz(sz, x2+(xFont-1)*gi.nScaleT, v + (yFont-2)*gi.nScaleT,
  1170.         dtLeft | dtBottom);
  1171.     }
  1172.  
  1173.     /* Now increment the day counter. For a month we always go up by one. */
  1174.     /* For a year we go up by four or until the end of the month reached. */
  1175.  
  1176.     if (yea) {
  1177.       day += 4;
  1178.       if (day > monsiz) {
  1179.         d += 4-(day-monsiz-1);
  1180.         if (d <= daytot + 1) {
  1181.           mon++;
  1182.           monsiz = DayInMonth(mon, Yea);
  1183.           day = 1;
  1184.         }
  1185.       } else
  1186.         d += 4;
  1187.     } else
  1188.       d++;
  1189.   }
  1190.   DrawColor(gi.kiLite);
  1191.   DrawEdge(x1, y1, x2, y2);
  1192.  
  1193.   ciCore = ciMain;    /* Recast original chart. */
  1194.   CastChart(fTrue);
  1195. }
  1196. #endif /* GRAPH */
  1197.  
  1198. /* xcharts1.c */
  1199.